﻿using System;
using System.Collections.Generic;
using System.Text;
using NKestrelClient.Memcache;
using System.Globalization;

namespace NKestrelClient.Kestrel
{
    public class KestrelClient
    {
        public interface IChannel : IDisposable 
        {
            void Set(string key, byte[] value);
            byte[] Get(string key);
        }
        
        class Channel : IChannel
        {
            public Channel(MemcachedClient core, PooledSocket socket) 
            {
                this.core = core;
                this.socket = socket;
            }

            MemcachedClient core;
            PooledSocket socket;

            public void Set(string key, byte[] value)
            {
                try
                {
                    SerializedType type = SerializedType.ByteArray;

                    string commandline = "set " + core.KeyPrefix + key + " " + (ushort)type + " " + 0 + " " + value.Length + "\r\n";

                    socket.Write(commandline);
                    socket.Write(value);
                    socket.Write("\r\n");
                    string response = socket.ReadResponse();
                    if (!response.StartsWith("STORED"))
                    {
                        throw new Exception("Response must be 'STORED' but was '" + response + "'");
                    }
                } catch(Exception) 
                {
                    socket.Close();
                    socket = null;
                    throw;
                }
            }

            public byte[] Get(string key) 
            {
                try
                {
                    socket.Write("get " + core.KeyPrefix + key + "\r\n");
                    string response = socket.ReadResponse();
                    string[] parts = response.Split(' '); //Result line from server: "VALUE <key> <flags> <bytes> <cas unique>"
                    if (parts[0] == "VALUE")
                    {
                        key = parts[1];
                        byte[] bytes = new byte[Convert.ToUInt32(parts[3], CultureInfo.InvariantCulture)];
                        socket.Read(bytes);
                        socket.SkipUntilEndOfLine(); //Skip the trailing \r\n
                        socket.ReadLine(); //Read the trailing END.
                        return bytes;
                    }
                    else if (parts[0] == "END") 
                    {
                        return null;
                    }
                    else throw new Exception("Unexpected response got '" + parts[0] + "' but 'VALUE' expected");
                }
                catch (Exception)
                {
                    socket.Close();
                    socket = null;
                    throw;
                }
            }
            
            public void Dispose()
            {
                if (socket != null) socket.Dispose();
            }
        }
        
        public KestrelClient(MemcachedClient client) 
        {
            this.core = client;
        }

        MemcachedClient core;

        public IChannel GetChannel(string key) 
        {
            var channel = new Channel(core, core.GetChannel(key));
            return channel;
        }
    }
}
